﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace LibSnesDotNet.Input
{
	public class Input
	{
		InputID _id;
		InputDimensionality _dimensionality;
		InputScale _scale;
		InputSemantic _semantic;

		public InputID ID { get { return _id; } }
		public InputDimensionality Dimensionality { get { return _dimensionality; } }
		public InputScale Scale { get { return _scale; } }
		public InputSemantic Semantic { get { return _semantic; } }

		public Input(InputID id, InputDimensionality dimensionality, InputScale scale, InputSemantic semantic)
		{
			_id = id;
			_dimensionality = dimensionality;
			_scale = scale;
			_semantic = semantic;
		}

		public Input(string driverName, string deviceName, string inputName,
		             InputDimensionality dimensionality, InputScale scale, InputSemantic semantic)
			: this(new InputID(driverName, deviceName, inputName), dimensionality, scale, semantic)
		{
		}
	}

	[TypeConverter(typeof(InputIDConverter))]
	public struct InputID
	{
		public static InputID Parse(string s)
		{
			s = s.Trim();

			if (string.IsNullOrEmpty(s)) { return new InputID(); }

			string[] parts = s.Split(':');
			return new InputID(parts[0], parts[1], parts[2]);
		}

		public string Name;
		public string DeviceName;
		public string DriverName;

		public InputID(string driverName, string deviceName, string name)
		{
			DriverName = driverName;
			DeviceName = deviceName;
			Name = name;
		}

		public override string ToString()
		{
			if (string.IsNullOrWhiteSpace(DriverName) || string.IsNullOrWhiteSpace(DeviceName) || string.IsNullOrWhiteSpace(Name))
			{
				return "";
			}

			var sb = new StringBuilder();

			sb.Append(DriverName);
			sb.Append(':');
			sb.Append(DeviceName);
			sb.Append(':');
			sb.Append(Name);

			return sb.ToString();
		}

		public override bool Equals(object obj)
		{
			return (obj is InputID && this == (InputID)obj);
		}

		public static bool operator ==(InputID lhs, InputID rhs)
		{
			return ReferenceEquals(lhs, rhs) ||
			       lhs.Name == rhs.Name && lhs.DeviceName == rhs.DeviceName && lhs.DriverName == rhs.DriverName;
		}

		public static bool operator !=(InputID lhs, InputID rhs)
		{
			return !(lhs == rhs);
		}

		public override int GetHashCode()
		{
			return (Name == null ? 0 : Name.GetHashCode()) +
			       (DeviceName == null ? 0 : DeviceName.GetHashCode()) +
			       (DriverName == null ? 0 : DriverName.GetHashCode());
		}
	}

	class InputIDConverter : TypeConverter
	{
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if (sourceType == typeof(string))
			{
				return true;
			}

			return base.CanConvertFrom(context, sourceType);
		}

		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			if (destinationType == typeof(string))
			{
				return true;
			}

			return base.CanConvertTo(context, destinationType);
		}

		public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
		{
			if (destinationType == typeof(string))
			{
				return value.ToString();
			}

			return base.ConvertTo(context, culture, value, destinationType);
		}

		public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
		{
			if (value is string)
			{
				try
				{
					return InputID.Parse((string)value);
				}
				catch
				{
					return null;
				}
			}

			return base.ConvertFrom(context, culture, value);
		}
	}
}
